using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
namespace DAL
{
    public class Forums : DAL.DataManager<Forum>
    {
        private static Forums Instance = new Forums();
        static Forums() { }

        public override string TableName
        {
            get { return @"yboard_forums"; }
        }

        public static string GetTableName()
        {
            return Instance.TableName;
        }

        protected override void CopyToItem(DataRow Row, Forum Item)
        {
            if (Row["ParentID"] != System.DBNull.Value)
            {
                Item.Parent = Forums.Item(Convert.ToInt64(Row["ParentID"]));
            }
            else
            {
                Item.Parent = null;
            }

            Item.Category = ForumCategories.Item(Convert.ToInt64(Row["CategoryID"]));

            Item.Name = Convert.ToString(Row["Name"]);

            if (Row["Description"] != System.DBNull.Value)
            {
                Item.Description = Convert.ToString(Row["Description"]);
            }
            else
            {
                Item.Description = null;
            }

            Item.Position = Convert.ToInt64(Row["Position"]);
            Item.TotalPosts = Convert.ToInt32(Row["TotalPosts"]);
            Item.TotalThreads = Convert.ToInt32(Row["TotalThreads"]);

            switch (Convert.ToInt32(Row["Status"]))
            {
                case 4:
                    Item.MinimumRequiredStatus = User.UserStatus.Administrator;
                    break;
                case 3:
                    Item.MinimumRequiredStatus = User.UserStatus.SuperModerator;
                    break;
                case 2:
                    Item.MinimumRequiredStatus = User.UserStatus.Moderator;
                    break;
                case 1:
                    Item.MinimumRequiredStatus = User.UserStatus.Member;
                    break;
                default:
                    Item.MinimumRequiredStatus = User.UserStatus.Unregistered;
                    break;
            }
        }

        protected override void CopyFromItem(DataManagerQuery query, Forum Item)
        {
            if (Item.Parent != null)
            {
                query.AddParam("ParentID", Item.Parent.ID);
            }
            else
            {
                query.AddParam("ParentID", System.DBNull.Value);
            }

            query.AddParam("Name", Item.Name);

            if (Item.Description != null)
            {
                query.AddParam("Description", Item.Description);
            }
            else
            {
                query.AddParam("Description", System.DBNull.Value);
            }

            query.AddParam("CategoryID", Item.Category.ID);

            query.AddParam("Position", Item.Position);

            query.AddParam("TotalPosts", Item.TotalPosts);

            query.AddParam("TotalThreads", Item.TotalThreads);

            switch (Item.MinimumRequiredStatus)
            {
                case User.UserStatus.Administrator:
                    query.AddParam("Status", 4);
                    break;
                case User.UserStatus.SuperModerator:
                    query.AddParam("Status", 3);
                    break;
                case User.UserStatus.Moderator:
                    query.AddParam("Status", 2);
                    break;
                case User.UserStatus.Member:
                    query.AddParam("Status", 1);
                    break;
                default:
                    query.AddParam("Status", 0);
                    break;
            }
        }

        public static Forum Item(Int64 id)
        {
            return Instance.GetItem(id);
        }

        private static void AddUserStatusParam(DataManagerQuery query)
        {
            User myUser = Managers.UserLoginManager.CurrentUser;
            if (myUser != null)
            {
                switch (myUser.Status)
                {
                    case User.UserStatus.Administrator:
                        query.AddParam("Status", Comparison.LessThanOrEqual, 4);
                        break;
                    case User.UserStatus.SuperModerator:
                        query.AddParam("Status", Comparison.LessThanOrEqual, 3);
                        break;
                    case User.UserStatus.Moderator:
                        query.AddParam("Status", Comparison.LessThanOrEqual, 2);
                        break;
                    case User.UserStatus.Member:
                        query.AddParam("Status", Comparison.LessThanOrEqual, 1);
                        break;
                    default:
                        query.AddParam("Status", 0);
                        break;
                }
            }
            else
            {
                query.AddParam("Status", 0);
            }
        }

        public static List<Forum> All()
        {
            DataManagerQuery query = new DataManagerQuery();
            AddUserStatusParam(query);
            return Instance.GetItems(query);
        }

        public static List<Forum> GetByCategory(ForumCategory category)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("CategoryID", category.ID);
            query.AddSort("Position", Sort.Asc);
            query.AddParam("ParentID", null);
            AddUserStatusParam(query);
            return Instance.GetItems(query);
        }

        public static void Add(Forum Item)
        {
            // user must be an administrator to add a forum
            User curUser = Managers.UserLoginManager.CurrentUser;
            if (curUser != null && curUser.HasPermissions(User.UserStatus.Administrator))
            {
                Instance.Insert(Item);
            }
            else
            {
                throw new ForumPermissionsException("Current user doesn't have enough permissions to add a forum.");
            }

            // after a forum is added, its "Position" should be equal to its current ID
            Item.Position = Item.ID;
            Save(Item);
        }

        public static void Save(Forum Item)
        {
            // user must be an administrator to add a forum
            Instance.Update(Item);
        }

        public static List<Forum> GetBreadcrumb(Forum baseItem)
        {
            List<Forum> myList = new List<Forum>();
            
            // I don't want to modify fromItem, so I have to store its ID in a temporary
            // variable.
            if (baseItem != null)
            {
                long originalID = baseItem.ID;

                while (baseItem != null)
                {
                    myList.Add(baseItem);
                    baseItem = baseItem.Parent;
                }

                // Restoring fromItem to original value
                baseItem = Item(originalID);
                myList.Reverse();
            }

            return myList;
        }

        public static List<Forum> GetByParent(Forum ParentForum)
        {
            DataManagerQuery query = new DataManagerQuery();
            AddUserStatusParam(query);
            if (ParentForum != null)
            {
                query.AddParam("ParentID", ParentForum.ID);
            }
            else
            {
                query.AddParam("ParentID", System.DBNull.Value);
            }
            query.AddSort("Position", Sort.Asc);

            return Instance.GetItems(query);
        }

        public static void Move(Forum Item, Direction dir)
        {
            //Helpers.PositionHelper<Forum> myPosition = new Helpers.PositionHelper<Forum>("ParentID", Item.Parent);
            //myPosition.MoveItem(Instance, Item, dir);
        }
    }

    public class Forum : DAL.DataManagerRow, IRowPosition
    {
        private Forum _Parent;
        public Forum Parent
        {
            get
            {
                return _Parent;
            }
            set
            {
                if (ContainsChildForum(value))
                {
                    string message = String.Format("'{0}' is a child of '{1}'. Parenting '{1}' to '{0}' results in a circular reference.",
                        value.Name, this.Name);
                    throw new ForumCircularReferenceException(message);
                }
                _Parent = value;
            }
        }

        private ForumCategory _Category;
        public ForumCategory Category
        {
            get
            {
                return _Category;
            }
            set
            {
                _Category = value;
            }
        }

        public bool ContainsChildForum(Forum testForum)
        {
            if (testForum != null)
            {
                if (testForum == this)
                {
                    return true;
                }

                Forum parent = testForum.Parent;
                while (parent != null)
                {
                    if (parent == this)
                    {
                        return true;
                    }
                    parent = parent.Parent;
                }
            }
            return false;
        }


        private string _Name;
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }


        private string _Description;
        public string Description
        {
            get
            {
                return _Description;
            }
            set
            {
                _Description = value;
            }
        }


        private Int64 _Position;
        public Int64 Position
        {
            get
            {
                return _Position;
            }
            set
            {
                _Position = value;
            }
        }


        private Int32 _TotalPosts;
        public Int32 TotalPosts
        {
            get
            {
                return _TotalPosts;
            }
            set
            {
                _TotalPosts = value;
            }
        }


        private Int32 _TotalThreads;
        public Int32 TotalThreads
        {
            get
            {
                return _TotalThreads;
            }
            set
            {
                _TotalThreads = value;
            }
        }

        public Thread GetLastThread()
        {
            return Threads.GetLastThreadByForum(this);
        }

        public int TotalPages
        {
            get
            {
                return (int)Math.Ceiling((double)(TotalThreads / 40));
            }
        }

        private DAL.User.UserStatus _status;
        public DAL.User.UserStatus MinimumRequiredStatus
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
            }
        }

        public List<Forum> GetChildForums()
        {
            return Forums.GetByParent(this);
        }
    }
}
